package Servlet;

import Service.AttachmentService;
import Service.UserService;
import entity.ArticleAttachment;
import entity.User;
import exception.BusinessException;
import utils.DBUtil;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * @Author Su
 * @Date 2025/5/2 16:38
 * @Version 1.0 （版本号）
 */


//业务：完整的附件下载功能，支持下载和预览两种模式
@WebServlet("/api/attachments/*")
public class AttachmentDownloadServlet extends HttpServlet {
    //文件传输缓冲区大小，设置为8KB(8192字节)，优化IO性能
    private static final int BUFFER_SIZE = 8192; // 8KB缓冲区
    private AttachmentService attachmentService;

    @Override
    public void init() throws ServletException {
        try {
            Connection connection = DBUtil.getConnection();
            this.attachmentService = new AttachmentService(connection);
        } catch (SQLException e) {
            throw new ServletException("初始化数据库连接失败", e);
        }
    }

    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

        try {
            //从session中获取当前user
            User user = (User) req.getSession().getAttribute("user");
            System.out.println("解析附件");


            //------------------路径解析
            // 1. 解析附件ID的url路径
            String pathInfo = req.getPathInfo(); // 格式: /{attachmentId}/[download|preview]
            String[] parts = pathInfo.split("/");
            int attachmentId = Integer.parseInt(parts[1]);

            //mode：判断是下载(download)还是预览(preview)，默认为下载
            String mode = parts.length > 2 ? parts[2] : "download";//三元运算


            //URL示例	                     parts数组	            mode值	行为
            ///api/attachments/123	        ["", "123"]	           download	强制下载文件
            ///api/attachments/123/preview	["", "123", "preview"]	preview	尝试浏览器内嵌显示


            // 2. 获取附件记录（带权限检查）先检查后获取
            System.out.println(attachmentService);
            ArticleAttachment attachment = attachmentService.getAttachmentWithAuthCheck(
                    attachmentId,user.getUserId()
            );
            // 3. 准备文件流
            //// 根据附件路径创建File对象
            File file = new File(attachment.getFilePath());
            if (!file.exists()) {//检查文件是否exist
                resp.sendError(HttpServletResponse.SC_NOT_FOUND);
                return;
            }

            // 4. 设置响应头
            //// 根据模式设置Content-Disposition头 contentdisposition内容处理
            if ("download".equals(mode)) {//download
                resp.setHeader("Content-Disposition",//响应体 服务器返回给客户端 告诉客户端必须下载
                        "attachment; filename=\"" + encodeFileName(attachment.getFileName(), req) + "\"");
            } else { // preview模式                       ////预览模式
                resp.setHeader("Content-Disposition", "inline");
            }

            //设置文件类型和长度
            resp.setContentType(attachment.getFileType());
            resp.setContentLengthLong(file.length());

            // 5. 流式传输文件
            // 使用try-with-resources自动关闭流
            try (InputStream in = new BufferedInputStream(new FileInputStream(file));
                 OutputStream out = new BufferedOutputStream(resp.getOutputStream())) {

                byte[] buffer = new byte[BUFFER_SIZE];
                int bytesRead;
                // 分块读取文件并写入响应
                while ((bytesRead = in.read(buffer)) != -1) {
                    out.write(buffer, 0, bytesRead);

                    //缓冲流：使用BufferedInputStream和BufferedOutputStream提高IO性能
                    //分块传输：避免一次性加载大文件到内存
                }
            }

        } catch (BusinessException e) {//业务异常403
            resp.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage());
        } catch (Exception e) {
            resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }

    // ----------处理中文文件名编码
    private String encodeFileName(String fileName, HttpServletRequest req) {
        String userAgent = req.getHeader("User-Agent");
        try {
            if (userAgent != null && userAgent.contains("MSIE")) {
                return URLEncoder.encode(fileName, "UTF-8");
            } else {
                return new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
            }
        } catch (Exception e) {
            return fileName;
        }
    }
}